﻿#region Copyright Statement
//  ------------------------------------------------------------------------------
//  
//    This file is part of The Streambolics Library.
//    Copyright © 2005-2009, Stephan Leclercq & Streambolics
//    All rights reserved.
//  
//    The Streambolics Library is free software; you can redistribute it and/or modify
//    it under the terms of the GNU General Public License as published by
//    the Free Software Foundation; either version 2 of the License, or
//    (at your option) any later version.
//  
//    The Streambolics Library is distributed in the hope that it will be useful,
//    but WITHOUT ANY WARRANTY; without even the implied warranty of
//    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
//    GNU General Public License for more details.
//  
//    You should have received a copy of the GNU General Public License
//    along with Streambolics; if not, write to the Free Software
//    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
//  
//  ------------------------------------------------------------------------------
#endregion

using System;
using System.Collections.Generic;
using System.Text;

namespace Streambolics.PatLite
{
    /// <summary>
    ///     A converter that will convert a wanted LightpoleStatus
    ///     to a PhcStatus.
    /// </summary>
    /// <remarks><para>
    ///     The converter silently ignores configurations it cannot
    ///     handle. For example, the white and blue lamps are ignored.
    /// </para></remarks>

    public class LightpoleToPhcConverter : IDisposable
    {
        private LightpoleStatus _Source;
        private PhcStatus _Destination;

        /// <summary>
        ///     Creates the converter.
        /// </summary>
        /// <param name="aSource">
        ///     The lightpole status that will be converted.
        /// </param>
        /// <param name="aDestination">
        ///     The PHC status that will be updated to reflect the changes in
        ///     the lightpole.
        /// </param>
        /// <remarks><para>
        ///     The converter will monitor the changes in the lightpole status
        ///     and reflect them in the PHC status, in real time.
        ///     To make a one-shot conversion, use the static Convert method.
        /// </para></remarks>

        public LightpoleToPhcConverter (LightpoleStatus aSource, PhcStatus aDestination)
        {
            _Source = aSource;
            _Destination = aDestination;
            _Source.Changed += new EventHandler (_Source_Changed);
        }

        #region Validation

        /// <summary>
        ///     Validates the source lightpole status.
        /// </summary>
        /// <remarks><para>
        ///     This method will throw an exception if the source status cannot
        ///     be converted to a PHC status.
        /// </para></remarks>

        public void ValidateSource ()
        {
            Validate (_Source);
        }

        /// <summary>
        ///     Validates a Lightpole Status.
        /// </summary>
        /// <param name="aSource">
        ///     The Lightpole Status to validate.
        /// </param>
        /// <remarks><para>
        ///     The method will throw an exception if the lightpole status
        ///     cannot be converted to a PHC status.
        /// </para></remarks>

        public static void Validate (LightpoleStatus aSource)
        {
            if (aSource.Blue != Lamp.Off || aSource.Blue != Lamp.Unknown)
            {
                throw new Exception ("Blue lamp is not supported");
            }
            if (aSource.White != Lamp.Off || aSource.White != Lamp.Unknown)
            {
                throw new Exception ("White lamp is not supported");
            }
        }

        #endregion

        #region Conversion

        private static void ConvertLamp (Lamp aLamp, PhcStatus aDestination, int aIndex)
        {
            switch (aLamp)
            {
                case Lamp.Off:
                    aDestination[aIndex] = Ternary.False;
                    aDestination[aIndex + 5] = Ternary.False;
                    break;

                case Lamp.On:
                    aDestination[aIndex] = Ternary.True;
                    aDestination[aIndex + 5] = Ternary.False;
                    break;
                
                case Lamp.Flashing:
                    aDestination[aIndex] = Ternary.False;
                    aDestination[aIndex + 5] = Ternary.True;
                    break;
            }
        }

        private static void ConvertSiren (Siren aSiren, PhcStatus aDestination, int aIndex)
        {
            switch (aSiren)
            {
                case Siren.Off:
                    aDestination[aIndex] = Ternary.False;
                    aDestination[aIndex + 1] = Ternary.False;
                    break;
                case Siren.Slow:
                    aDestination[aIndex] = Ternary.False;
                    aDestination[aIndex + 1] = Ternary.True;
                    break;
                case Siren.Fast:
                    aDestination[aIndex] = Ternary.True;
                    aDestination[aIndex + 1] = Ternary.False;
                    break;
            }
        }

        /// <summary>
        ///     Converts the wanted lightpole status given as source
        ///     to a needed status of the PHC controller.
        /// </summary>
        /// <param name="aSource">
        ///     The wanted Lightpole status
        /// </param>
        /// <param name="aDestination">
        ///     The corresponding PHC status.
        /// </param>

        public static void Convert (LightpoleStatus aSource, PhcStatus aDestination)
        {
            ConvertLamp (aSource.Red, aDestination, 0);
            ConvertLamp (aSource.Amber, aDestination, 1);
            ConvertLamp (aSource.Green, aDestination, 2);
            ConvertSiren (aSource.Siren, aDestination, 3);
        }

        private void _Source_Changed (object sender, EventArgs e)
        {
            Convert (_Source, _Destination);
        }

        #endregion

        #region IDisposable Members

        public void Dispose ()
        {
            _Source.Changed -= new EventHandler (_Source_Changed);
        }

        #endregion
    }
}
